# encoding: utf-8
from __future__ import unicode_literals

import copy

from django import forms
from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.db import models


class ModelAdmin(admin.ModelAdmin):
    # class Media:
    #     css = {'all': ['css/select2.min.css']}
    #     js = ['js/select2.js', 'django_select2/django_select2.js']

    change_list_template = 'suit3/change_list.html'
    change_form_template = 'suit3/change_form.html'
    exclude = []
    formfield_overrides = {
        # models.ForeignKey: {'widget': Select2Widget},
        # models.ManyToManyField: {'widget': Select2MultipleWidget},
        models.TextField: {'widget': forms.Textarea(attrs={'rows': 4, 'cols': 40})}
    }

    def have_add_permission(self, request):
        return super(ModelAdmin, self).has_add_permission(request)

    def have_change_permission(self, request, obj=None):
        return super(ModelAdmin, self).has_change_permission(request, obj)

    def have_delete_permission(self, request, obj=None):
        return super(ModelAdmin, self).has_delete_permission(request, obj)

    def has_add_permission(self, request):
        return request.user.is_superuser or self.have_add_permission(request)

    def has_view_permission(self, request, obj=None):
        view_permission = 'view_%s' % self.opts.model_name
        # view_permission = 'view_%s' % self.model._meta.model_name
        return request.user.has_perm(self.opts.app_label + '.' + view_permission)

    def has_change_permission(self, request, obj=None):
        return request.user.is_superuser or (self.have_change_permission(request, obj) or
                                             self.has_view_permission(request, obj))

    def has_delete_permission(self, request, obj=None):
        return request.user.is_superuser or self.have_delete_permission(request, obj)

    def get_model_perms(self, request):
        value = super(ModelAdmin, self).get_model_perms(request)
        value['view'] = self.has_view_permission(request)
        return value

    def get_actions(self, request):
        value = super(ModelAdmin, self).get_actions(request)
        if not request.user.is_superuser:
            if 'delete_selected' in value:
                del value['delete_selected']
        return value

    def get_fieldsets(self, request, obj=None):
        if not self.fieldsets:
            return super(ModelAdmin, self).get_fieldsets(request, obj)
        has_fieldsets = False
        fieldsets = copy.deepcopy(self.fieldsets)
        if type(fieldsets) == tuple:
            fieldsets = list(fieldsets)
            has_fieldsets = True
        fieldset_offset = 0
        for fieldset_i, fieldset in enumerate(fieldsets[:]):
            has_fields = False
            fields = fieldsets[fieldset_i - fieldset_offset][1]['fields']
            if type(fieldsets[fieldset_i - fieldset_offset][1]['fields']) == tuple:
                fields = list(fieldsets[fieldset_i - fieldset_offset][1]['fields'])
                has_fields = True
            field_offset = 0
            for field_i, field in enumerate(fields[:]):
                if type(field) == tuple:
                    cols = list(field)
                    for col in cols[:]:
                        if col in self.exclude:
                            cols.remove(col)
                    if len(cols) == 0:
                        fields.remove(field)
                        field_offset += 1
                    elif len(cols) == 1:
                        fields[field_i - field_offset] = cols[0]
                else:
                    if self.exclude is not None and field in self.exclude:
                        fields.remove(field)
            if len(fields) == 0:
                fieldsets.remove(fieldset)
                fieldset_offset += 1
            else:
                if has_fields:
                    fieldsets[fieldset_i - fieldset_offset][1]['fields'] = tuple(fields)
                else:
                    fieldsets[fieldset_i - fieldset_offset][1]['fields'] = fields
        if has_fieldsets:
            return tuple(fieldsets)
        return fieldsets

    def get_readonly_fields(self, request, obj=None):
        change = obj is not None
        view_perm = self.has_view_permission(request, obj)
        change_perm = self.have_change_permission(request, obj)
        if change and view_perm and not change_perm:
            readonly_fields = [x.name for x in self.opts.many_to_many]
            readonly_fields += [x.name for x in self.opts.fields if x.name != u'id']  # exclude
            return readonly_fields
        return self.readonly_fields

    def change_view(self, request, object_id, form_url='', extra_context=None):
        extra_context = extra_context or {}
        extra_context.update({'has_change': self.have_change_permission(request)})
        return super(ModelAdmin, self).change_view(request, object_id, form_url, extra_context)


class TabularInline(admin.TabularInline):
    template = 'suit3/edit_inline/tabular.html'
    exclude = []
    formfield_overrides = {
        # models.ForeignKey: {'widget': Select2Widget},
        # models.ManyToManyField: {'widget': Select2MultipleWidget},
        models.TextField: {'widget': forms.Textarea(attrs={'rows': 2, 'cols': 40})}
    }

    def have_add_permission(self, request):
        return super(TabularInline, self).has_add_permission(request)

    def have_change_permission(self, request, obj=None):
        return super(TabularInline, self).has_change_permission(request, obj)

    def have_delete_permission(self, request, obj=None):
        return super(TabularInline, self).has_delete_permission(request, obj)

    def has_add_permission(self, request):
        return request.user.is_superuser or self.have_add_permission(request)

    def has_view_permission(self, request, obj=None):
        view_permission = 'view_%s' % self.opts.model_name
        # view_permission = 'view_%s' % self.model._meta.model_name
        return request.user.has_perm(self.opts.app_label + '.' + view_permission)

    def has_change_permission(self, request, obj=None):
        return request.user.is_superuser or (self.have_change_permission(request, obj) or
                                             self.has_view_permission(request, obj))

    def has_delete_permission(self, request, obj=None):
        return request.user.is_superuser or self.have_delete_permission(request, obj)

    def get_model_perms(self, request):
        value = super(TabularInline, self).get_model_perms(request)
        value['view'] = self.has_view_permission(request)
        return value

    def get_readonly_fields(self, request, obj=None):
        change = obj is not None
        add_perm = self.has_add_permission(request)
        view_perm = self.has_view_permission(request, obj)
        change_perm = self.have_change_permission(request, obj)
        if change and view_perm and not change_perm and not add_perm:
            readonly_fields = [x.name for x in self.opts.many_to_many]
            readonly_fields += [x.name for x in self.opts.fields if x.name != u'id']  # exclude
            return readonly_fields
        return self.readonly_fields

    def get_fieldsets(self, request, obj=None):
        if not self.fieldsets:
            return super(TabularInline, self).get_fieldsets(request, obj)
        has_fieldsets = False
        fieldsets = copy.deepcopy(self.fieldsets)
        if type(fieldsets) == tuple:
            fieldsets = list(fieldsets)
            has_fieldsets = True
        fieldset_offset = 0
        for fieldset_i, fieldset in enumerate(fieldsets[:]):
            has_fields = False
            fields = fieldsets[fieldset_i - fieldset_offset][1]['fields']
            if type(fieldsets[fieldset_i - fieldset_offset][1]['fields']) == tuple:
                fields = list(fieldsets[fieldset_i - fieldset_offset][1]['fields'])
                has_fields = True
            field_offset = 0
            for field_i, field in enumerate(fields[:]):
                if type(field) == tuple:
                    cols = list(field)
                    for col in cols[:]:
                        if col in self.exclude:
                            cols.remove(col)
                    if len(cols) == 0:
                        fields.remove(field)
                        field_offset += 1
                    elif len(cols) == 1:
                        fields[field_i - field_offset] = cols[0]
                else:
                    if self.exclude is not None and field in self.exclude:
                        fields.remove(field)
            if len(fields) == 0:
                fieldsets.remove(fieldset)
                fieldset_offset += 1
            else:
                if has_fields:
                    fieldsets[fieldset_i - fieldset_offset][1]['fields'] = tuple(fields)
                else:
                    fieldsets[fieldset_i - fieldset_offset][1]['fields'] = fields
        if has_fieldsets:
            return tuple(fieldsets)
        return fieldsets

    def get_formset(self, request, obj=None, **kwargs):
        formset = super(TabularInline, self).get_formset(request, obj, **kwargs)
        formset.has_add = self.has_add_permission(request)
        formset.has_change = request.user.is_superuser or self.have_change_permission(request, obj)
        return formset


class StackedInline(TabularInline):
    template = 'suit3/edit_inline/stacked.html'


class InlineChangeList(object):
    can_show_all = True
    multi_page = True
    get_query_string = ChangeList.__dict__['get_query_string']

    def __init__(self, request, page_num, paginator):
        self.show_all = 'all' in request.GET
        self.page_num = page_num
        self.paginator = paginator
        self.result_count = paginator.count
        self.params = dict(request.GET.items())


class PaginationInline(TabularInline):
    template = 'suit3/edit_inline/tabular_paginated.html'
    per_page = 20

    def get_formset(self, request, obj=None, **kwargs):
        formset_class = super(PaginationInline, self).get_formset(
            request, obj, **kwargs)

        class PaginationFormSet(formset_class):
            def __init__(self, *args, **kwargs):
                super(PaginationFormSet, self).__init__(*args, **kwargs)

                qs = self.queryset
                paginator = Paginator(qs, self.per_page)
                try:
                    page_num = int(request.GET.get('p', '0'))
                except ValueError:
                    page_num = 0

                try:
                    page = paginator.page(page_num + 1)
                except (EmptyPage, InvalidPage):
                    page = paginator.page(paginator.num_pages)

                self.cl = InlineChangeList(request, page_num, paginator)
                self.paginator = paginator

                if self.cl.show_all:
                    self._queryset = qs
                else:
                    self._queryset = page.object_list

        PaginationFormSet.per_page = self.per_page
        return PaginationFormSet
